/***********************************************************************
 * Module:  Damier.java
 * Author:  nabil
 * Purpose: Defines the Class Damier
 ***********************************************************************/
package model.jeu_de_dame;

import model.util.Couleur;
import model.util.Direction;
import controller.PartieController;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Observable;

 /**
 * <b>Damier représente la structure du jeu et contient les cases, les pieces du jeu.
 *    Elle contient aussi certains paramètres tel que le nombre de cases, la couleur 
 *    des cases autorisés pour le déplacement, le nombre de pieces blanches et noirs...
 * </b>
  * <p>
 * Un damier est caractérisé par les informations suivantes :
 * <ul>
 * <li>Le nombre de pieces blanches en jeu</li>
 * <li>Le nombres de pieces noirs en jeu</li>
 * <li>La couleur des cases autorisés pour le déplacement</li>
 * <li>La matrice des cases du damier</li>
 * <li>La matrice des pièces sur le damier</li>
 * </ul>
 * </p>
 * @see PartieController
 * @see Partie
 * @see Observable
 * @author nabil mansouri
 * @version 2.0
 */
public class Damier{
    /**
         * La taille, soit le nombre de case par côtés. Cette variable est static.
         * 
         * @see Damier#Damier() 
         */
    protected static final int taille = 10;
    /**
         * Le nombre total de piece par damier (blanches et noirs). Cette variable est static.
         * 
         * @see Damier#initialisationPionBlanc()  
         * @see Damier#initialisationPionNoir()    
         */
    protected static final int nbPion = 40; 
        /**
         * Le nombre de pieces blanches actuellement sur le damier
         * 
         * @see Damier#initialisationPionBlanc()
         * @see Damier#supprimerPiece(model.Piece) 
         */
    protected int nbPionBlanc;
       /**
         * Le nombre de pieces noirs actuellement sur le damier
         *  
         * @see Damier#initialisationPionNoir() 
         * @see Damier#supprimerPiece(model.Piece) 
         */
    protected int nbPionNoir;
    
    /**
         * La couleur des cases sur lesquels jouer.
         *  
         * @see Damier#initialisationCases() 
         * @see Piece#seDeplacer(model.Case)  
         */
    protected Couleur couleurDeJeu;
      /**
         * La matrice des cases du damier. Elle permet de retrouver une case rapidement via ses coordonnées
         * Exemple : La case (x,y) se situe dans mesCases[y][x]
         *  
         * @see Damier#initialisationCases() 
         * @see Damier#getCase(int, int)   
         */
    protected Case [][] mesCases;
       /**
         * La matrice des pieces du damier. Elle permet de retrouver une piece rapidement via ses coordonnées
         * Exemple : La piece (x,y) se situe dans mesPieces[y][x]
         *  
         * @see Damier#initialisationPionBlanc()  
         * @see Damier#initialisationPionNoir()  
         * @see Damier#getPiece(int, int)    
         */
    protected Piece [][] mesPieces;
   
       /**
         * Constructeur Damier.
         * <p>
         * A la construction d'un objet Damier, les cases et les pieces sont crées puis placés 
         * sur celui ci selon les règles du jeu de dame. Puis ceux ci sont enregistrer via leurs coordonnées.
     *   * La couleur par défaut des cases autorisés est "noir";
         * </p>
         * @see Damier#initialisation() 
         * @see Damier#initialisationCases() 
         * @see Damier#initialisationPionBlanc() 
         * @see Damier#initialisationPionNoir()  
         */
    
   public Damier()
   {    try {
            //on cree notre jeu avec nos cases et nos pions
               this.couleurDeJeu = Couleur.NOIR;
               mesCases = new Case[taille][taille];
               mesPieces = new Piece[taille][taille];
               initialisationCases();
               initialisation();
        } catch (Exception ex) {
        }
   }
   
  /**
     * Initialise seulement les pions du damier. Si cette méthode est appelé, les cases existent déjà
     * il n'est donc pas nécessaires de les réinitialiser.
     * 
     * @see Damier#initialisationPionBlanc() 
     * @see Damier#initialisationPionNoir()
     */
   public void initialisation()
   {    try {
            //on réinit juste les pion
               initialisationPionBlanc();
               initialisationPionNoir();
        } catch (Exception ex) {
        }
       
   }
   
     /**
     * Initialise seulement les cases du damier selon le respect des couleurs. Ces cases sont ensuites
    *  enregistré dans la matrice des cases
     * 
     */
   private void initialisationCases()
   {
       boolean blanc = false;Couleur couleur;
       //init des cases
        for(int i = 0; i<mesCases.length; i++)
        {
            blanc = !blanc;
            for(int j=0;j<mesCases[i].length;j++)
            {    
                if(blanc)couleur = Couleur.BLANC;
                else couleur = Couleur.NOIR;
                mesCases[i][j] = new Case(j,i,couleur,this);
                blanc=!blanc;                
            }
        }
        for(int i = 0; i<mesCases.length; i++)
        {
            for(int j=0;j<mesCases[i].length;j++)
            {    
                try
                {
                    mesCases[i][j].setVoisine(Direction.NORD_OUEST, mesCases[i-1][j-1]);
                }catch(Exception e){}
                try
                {
                    mesCases[i][j].setVoisine(Direction.NORD_EST, mesCases[i-1][j+1]);
                }catch(Exception e){}
                try
                {
                    mesCases[i][j].setVoisine(Direction.SUD_EST, mesCases[i+1][j+1]);
                }catch(Exception e){}
                try
                {
                    mesCases[i][j].setVoisine(Direction.SUD_OUEST, mesCases[i+1][j-1]);
                }catch(Exception e){}
            }
        }
   }
   
   /**
     * Initialise seulement les pions blanc du damier selon le respect des couleurs et des positions. Ces pions sont ensuite
     *  enregistré dans la matrice des cases
     * 
     */
   private void initialisationPionBlanc() throws Exception
   {
       for(int i = 0; i<mesCases.length && nbPionBlanc<nbPion/2; i++)
        {
            for(int j=0;j<mesCases[i].length && nbPionBlanc<nbPion/2 ;j++)
            {  
                Case c = mesCases[i][j];
                if(c.getCouleur()==couleurDeJeu)
                {
                    mesPieces[i][j] =FactoryPiece.getInstance().createPiece(FactoryPiece.Type.PION, this, Couleur.BLANC, j, i);
                    mesPieces[i][j].setDirection(Direction.SUD);
                    this.nbPionBlanc++;
                }
                
            }
        }
   }
   
   /**
     * Initialise seulement les pions noirs du damier selon le respect des couleurs et des positions. Ces pions sont ensuite
     *  enregistré dans la matrice des cases
     * 
     */
   private void initialisationPionNoir() throws Exception
   {
       for(int i = mesCases.length-1; i>= 0 && nbPionNoir<nbPion/2; i--)
        {
            for(int j=0;j<mesCases[i].length && nbPionNoir<nbPion/2 ;j++)
            {  
                Case c = mesCases[i][j];
                if(c.getCouleur()==couleurDeJeu)
                {
                    mesPieces[i][j] =FactoryPiece.getInstance().createPiece(FactoryPiece.Type.PION, this, Couleur.NOIR, j, i);
                    mesPieces[i][j].setDirection(Direction.NORD);
                    this.nbPionNoir++;
                }
            }
        }
//        for(int i = mesCases.length-1; i>= 0 && nbPionNoir<nbPion/2; i--)
//        {
//            for(int j=0;j<mesCases[i].length && nbPionNoir<nbPion/2 ;j++)
//            {  
//                Case c = mesCases[i][j];
//                if(c.getCouleur().equalsIgnoreCase(couleurDeJeu))
//                {
//                    mesPieces[i][j] = new Dame(this,j,i,"noir");
//                    this.nbPionNoir++;
//                }
//            }
//           }
   }
   
   /**
     * Retourne la matrice des cases du damier. Il y a correspondance avec les coordonnées de chaque case
    *  et la position dans la matrice
     * 
     */
   public Case[][] getMesCases() {
      return mesCases;
   }
   
  /**
     * Retourne la matrice des pieces du damier. Il y a correspondance avec les coordonnées de chaque piece
     *  et la position dans la matrice
     * 
     */
    public Piece[][] getMesPieces() {
      return mesPieces;
   }

  /**
     * Retourne si la case qui a pour abscisse x et coordonné y
     * @param x
     *            La coordonnée sur l'axe des absisses x
     * @param y
     *            La coordonnée sur l'axe des ordonnées
     * 
     * @return Retourne la case à la position (x,y) ou null si elle n'existe pas
     * 
     */
   public Case getCase(int x, int y) throws Exception
   {
       Case c = null;
       try
       {
            c=  mesCases[y][x];
       }
       catch(Exception e)
       {
           throw new Exception("La case n'existe pas");
       }
       return c;
   }
   
     /**
     * Enregistre la piece c dans la matrice des pieces aux coordonnées (x,y). 
     * Plus précisément, une position est affécté à la piece.
     * @param c
     *            La piece qui sera enregistré dans la matrice
     * @param x
     *            La coordonnée sur l'axe des absisses 
     * @param y
     *            La coordonnée sur l'axe des ordonnées
     * 
     * 
     */
   public void setPiece(Piece c, int x, int y) {
     if(c!=null)
     {
       c.setPositionX(x);
       c.setPositionY(y);
         
     }
     mesPieces[y][x]=c;
     mesCases[y][x].setChangement();
   }
   
     /**
     * Retourne la piece qui est à la position (x,y) ou null si la position n existe pas
     * @param x
     *            La coordonnée sur l'axe des absisses 
     * @param y
     *            La coordonnée sur l'axe des ordonnées
     * 
     * @return Retourne la piece à la position (x,y) ou null si elle n'existe pas
     * 
     */   
   public Piece getPiece(int x, int y) throws Exception
   {
       Piece c;
       try{
           c=  mesPieces[y][x];
       }
      catch(Exception e)
      {
          c = null;
      }
       return c;
   }

    
  /**
     * Retourne la couleur des cases autorisés "blanc" ou "noir"
     * 
     * @return Retourne la couleur des cases autorisés "blanc" ou "noir"
     * 
     */
    public Couleur getCouleurJeu()
    {
        return this.couleurDeJeu;
    }
    
      /**
     * Retourne vrai si la piece p a été supprimé du damier, faux sinon. 
     * Si la piece est blanche nbPionBlanc est décrémenté sinon nbPionNoir est décrémenté
     * @param p
     *          La piece a supprimé
     * @return Retourne vrai si la piece a été supprimé
     * 
     */
    public boolean supprimerPiece(Piece p)
    {
        int x = p.getPositionX();
        int y = p.getPositionY();
        this.setPiece(null,x, y);
        p.setPositionX(-1);
        p.setPositionY(-1);
        mesCases[y][x].setChangement();
        if(p.getCouleur()==Couleur.NOIR)
                this.nbPionNoir--;
        else
            this.nbPionBlanc--;
        
        return true;
    }
   /**
     * Retourne la taille du damier. Cette méthode est static
     * 
     * @return Retourne nombre de cases par côté
     * 
     */
    public static int getTaille()
    {
        return taille;
    }
    

    public Couleur getCouleurPiece(int x, int y) throws Exception
    {
         return getPiece(x, y).getCouleur();
    }
    
    
    public void affecterPiece(Case c, Piece p)
    {
        this.setPiece(null, p.getPositionX(), p.getPositionY());
        mesCases[p.getPositionY()][p.getPositionX()].setChangement();
        this.setPiece(p, c.getPositionX(), c.getPositionY());
        c.setChangement();
        
    }
     
    public void maj()
    {
        ArrayList<Case>liste = new ArrayList<Case>();
        for(int i = 0;i<mesCases.length;i++)
        {
            for(int j = 0; j<mesCases.length;j++)
            {
                if(mesPieces[i][j]!=null && mesPieces[i][j].isSelected())
                {
                    liste = mesPieces[i][j].getCasesAccessibles();
                }
                this.mesCases[i][j].setAccessible(false);
                this.mesCases[i][j].maj();
            }
        }
        for(Case  c : liste )
        {
            c.setAccessible(true);
            c.maj();
        }
    }

    public int getNbPionBlanc() {
        return nbPionBlanc;
    }

    public int getNbPionNoir() {
        return nbPionNoir;
    }

    public void setMesPieces(Piece[][] mesPieces) {
        this.mesPieces = mesPieces;
    }
    
    public ArrayList<Piece> getPieces(Couleur c)
    {
        ArrayList<Piece> res = new ArrayList<Piece>();
        for(int i = 0; i< mesPieces.length;i++)
        {
            for(Piece p : mesPieces[i])
                if(p!=null && p.getCouleur()==c)
                    res.add(p);
                    
        }
        return res;
    }

}